from flask import Blueprint, request, jsonify
import os
import pdfplumber
import warnings
import requests
import tempfile
import logging
from logging.handlers import TimedRotatingFileHandler
import os
# 创建蓝图
pdf_table_bp = Blueprint('pdf_table', __name__)

# 配置日志


# 确保日志目录存在
os.makedirs('./logs', exist_ok=True)

# 创建按天滚动的日志处理器
handler = TimedRotatingFileHandler(
    './logs/error.log',
    when='midnight',  # 每天午夜滚动
    backupCount=7,  # 保留7天的日志
    encoding='utf-8'
)
handler.setFormatter(logging.Formatter('%(asctime)s - %(levelname)s - %(message)s'))
logging.basicConfig(level=logging.INFO, handlers=[handler])


def is_same_table(prev_table, current_table, min_col_match=3, header_similarity=0):
    """
    判断两个表格是否为跨页的同一表格
    :param prev_table: 前一页的最后一个表格
    :param current_table: 当前页的第一个表格
    :param min_col_match: 最小匹配列数（默认3列一致则认为连续）
    :param header_similarity: 表头相似度阈值（0.8表示80%相似）
    """
    if not prev_table or not current_table:
        return False

    # 判断列数是否一致
    if len(prev_table[0]) != len(current_table[0]):
        return False
    # 检查表头相似性（如果前一页的最后一行是表头，则跳过）
    prev_header = prev_table[0]
    current_header = current_table[0]
    # 增加空值检查
    if not all(prev_header) or not all(current_header):
        return False

    # 计算表头匹配的列数
    match_count = sum(1 for p, c in zip(prev_header, current_header) if p == c)
    if match_count >= min_col_match or (match_count / len(prev_header)) >= header_similarity:
        return True

    return False


def merge_tables(prev_table, current_table):
    """合并两个连续表格（去除重复表头）"""
    merged = prev_table.copy()

    # 检查是否需要去重：如果最后一行的内容与当前表格第一行重复
    last_row_prev = merged[-1]
    first_row_current = current_table[0]

    if last_row_prev == first_row_current:
        merged.extend(current_table[1:])
    else:
        merged.extend(current_table)

    return merged


def extract_pdf_tables(pdf_path):
    """提取PDF表格（支持跨页合并）"""
    all_tables = []
    ongoing_table = None  # 暂存跨页未完成的表格

    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            # 提取当前页所有表格
            tables = page.extract_tables({
                "vertical_strategy": "lines",
                "horizontal_strategy": "lines",
                "explicit_vertical_lines": [],
                "explicit_horizontal_lines": []
            })

            # 清洗和标准化表格数据
            cleaned_tables = []
            for table in tables:
                cleaned = [
                    [str(cell).replace('\n', ' ').strip() if cell is not None else ""
                     for cell in row
                     ] for row in table
                ]
                cleaned_tables.append(cleaned)

            # 跨页合并逻辑
            if not cleaned_tables:
                continue

            if ongoing_table is not None:
                # 只尝试合并当前页的第一个表格
                first_current = cleaned_tables[0]
                if is_same_table(ongoing_table, first_current):
                    ongoing_table = merge_tables(ongoing_table, first_current)
                    cleaned_tables = cleaned_tables[1:]  # 移除已合并的表格
                else:
                    all_tables.append(ongoing_table)
                    ongoing_table = None

            # 处理当前页剩余的表格
            for idx, table in enumerate(cleaned_tables):
                if idx == 0 and ongoing_table is None:
                    ongoing_table = table
                else:
                    if ongoing_table is not None:
                        all_tables.append(ongoing_table)
                        ongoing_table = None
                    all_tables.append(table)

    # 添加最后一个未完成的表格
    if ongoing_table is not None:
        all_tables.append(ongoing_table)

    return all_tables


def extract_tables(file_path):
    """自动识别文件类型并提取表格"""
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"文件不存在：{file_path}")

    ext = os.path.splitext(file_path)[1].lower()
    if ext == '.pdf':
        all_tables = extract_pdf_tables(file_path)
    elif ext == '.docx':
        from routers.doc2table import extract_word_tables
        all_tables = extract_word_tables(file_path)
    else:
        raise ValueError("不支持的文件格式，仅支持pdf和docx")

    return all_tables


def format_table_to_markdown(table):
    if not table or len(table) == 0:
        return ""

    try:
        # 确保所有行长度一致
        max_cols = max(len(row) for row in table)
        table = [row + [""] * (max_cols - len(row)) for row in table]

        separator = ["---"] * max_cols
        markdown_table = [
            "| " + " | ".join(str(cell) for cell in table[0]) + " |",
            "| " + " | ".join(separator) + " |"
        ]
        markdown_table.extend(
            "| " + " | ".join(str(cell) for cell in row) + " |"
            for row in table[1:]
        )
        return "\n".join(markdown_table)
    except Exception as e:
        error_msg = f"格式化表格出错: {str(e)}"
        logging.error(error_msg)
        print(error_msg)
        return ""


def format_table_to_html(table):
    if not table or len(table) == 0:
        return ""
    try:
        html_table = ['<table>']
        for i, row in enumerate(table):
            tag = 'th' if i == 0 else 'td'
            html_row = ['<tr>']
            for cell in row:
                html_row.append(f'<{tag}>{str(cell)}</{tag}>')
            html_row.append('</tr>')
            html_table.extend(html_row)
        html_table.append('</table>')
        return ''.join(html_table)
    except Exception as e:
        error_msg = f"格式化表格出错: {str(e)}"
        logging.error(error_msg)
        print(error_msg)
        return ""


# 修改路由装饰器
@pdf_table_bp.route('/extract_tables', methods=['POST'])
def api_extract_tables():
    try:
        body = request.get_json()
        if not body or not isinstance(body, dict):
            return jsonify({
                "code": 2,
                "msg": "Invalid request body"
            }), 200

        file_url = body.get("fileUrl")
        if not file_url:
            return jsonify({
                "code": 2,
                "msg": "Missing required parameter: fileUrl"
            }), 200

        # URL验证
        try:
            from urllib.parse import urlparse, unquote
            parsed = urlparse(file_url)
            if not all([parsed.scheme, parsed.netloc]):
                return jsonify({
                    "code": 2,
                    "msg": "Invalid URL format"
                }), 200
            # 提取路径部分并解码
            path = unquote(parsed.path)
            filename = os.path.basename(path)
        except Exception as e:
            return jsonify({
                "code": 0,
                "msg": f"URL验证失败: {str(e)}"
            }), 200

        # 文件扩展名验证
        if not filename.lower().endswith(('.pdf', '.docx')):
            return jsonify({
                "code": 2,
                "msg": "仅支持pdf和docx文件"
            }), 200

        # 生成临时文件路径
        suffix = '.pdf' if filename.lower().endswith('.pdf') else '.docx'
        temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix)
        temp_file.close()

        # 下载文件
        try:
            response = requests.get(file_url, stream=True, timeout=30)
            response.raise_for_status()

            # 文件大小限制(10MB)
            content_length = int(response.headers.get('content-length', 0))
            if content_length > 10 * 1024 * 1024:
                return jsonify({
                    "data": {},
                    "code": 2,
                    "msg": "File size exceeds 10MB limit"
                }), 200
        except requests.RequestException as e:
            return jsonify({
                "data": {},
                "code": 2,
                "msg": f"文件下载失败: {str(e)}"
            }), 200

        # 处理临时文件
        try:
            with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as temp_file:  # 修改这里，使用变量suffix
                file_path = temp_file.name
                # 检查文件权限
                if not os.access(file_path, os.W_OK):
                    return jsonify({
                        "code": 2,
                        "msg": "临时文件没有写入权限"
                    }), 200
                for chunk in response.iter_content(chunk_size=8192):
                    temp_file.write(chunk)
        except Exception as e:
            cleaned_msg = str(e).replace('\n', '')
            return jsonify({
                "data": {},
                "code": 2,
                "msg": f"临时文件保存失败: {cleaned_msg}"
            }), 200

        # 验证PDF文件
        try:
            # 验证文件类型
            with open(file_path, 'rb') as f:
                file_header = f.read(4)
                if suffix == '.pdf' and file_header != b'%PDF':
                    os.remove(file_path)
                    cleaned_msg = "下载的文件不是有效的PDF".replace('\n', '')
                    return jsonify({
                        "data": {},
                        "code": 2,
                        "msg": cleaned_msg
                    }), 200
                elif suffix == '.docx' and file_header != b'PK\x03\x04':
                    os.remove(file_path)
                    cleaned_msg = "下载的文件不是有效的DOCX".replace('\n', '')
                    return jsonify({
                        "data": {},
                        "code": 2,
                        "msg": cleaned_msg
                    }), 200

        except Exception as e:
            cleaned_msg = str(e).replace('\n', '')
            return jsonify({
                "data": {},
                "code": 2,
                "msg": f"验证文件时出错: {cleaned_msg}"
            }), 200

        # 提取表格
        try:
            all_tables = extract_tables(file_path)
            if len(all_tables) == 0:
                return jsonify({
                    "code": 2,
                    "msg": "文档中找不到表格",
                    "data": None
                })

            return jsonify({
                "code": 1,
                "msg": "",
                "data": {
                    "tables": [format_table_to_html(table) for table in all_tables]
                }
            })
        except Exception as e:
            return jsonify({
                "code": 2,
                "data": {},
                "msg": f"表格提取失败: {str(e)}"
            }), 200
        finally:
            try:
                os.remove(file_path)
            except:
                pass

    except Exception as e:
        error_msg = f"意外错误: {str(e)}"
        logging.error(error_msg)
        return jsonify({
            "data": {},
            "code": 2,
            "msg": f"Unexpected error: {str(e)}"
        }), 500
